﻿using OxyPlot.SkiaSharp;
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace OxyPlot.CatExtension.Skia
{
    public static class OxyExtensions
    {
        [UnsafeAccessor(UnsafeAccessorKind.Method, Name = nameof(GetPath))]
        static extern SKPath GetPath(SkiaRenderContext context);
        [UnsafeAccessor(UnsafeAccessorKind.Method, Name = nameof(GetLinePaint))]
        static extern SKPaint GetLinePaint(SkiaRenderContext context, OxyColor strokeColor, double strokeThickness, EdgeRenderingMode edgeRenderingMode, double[]? dashArray, LineJoin lineJoin);
        [UnsafeAccessor(UnsafeAccessorKind.Method, Name = nameof(GetSnapOffset))]
        static extern float GetSnapOffset(SkiaRenderContext context, double thickness, EdgeRenderingMode edgeRenderingMode);

        public static void DrawLine(
            this SkiaRenderContext context,
            Span<float> pointsX,
            Span<float> pointsY,
            OxyColor stroke,
            double thickness,
            EdgeRenderingMode edgeRenderingMode,
            double[]? dashArray = null,
            LineJoin lineJoin = LineJoin.Miter
        )
        {
            var path = GetPath(context);
            var paint = GetLinePaint(context, stroke, thickness, edgeRenderingMode, dashArray, lineJoin);

            //var rendersToPixels = context.RenderTarget != RenderTarget.VectorGraphic;
            //var isStraightLine = rendersToPixels ? IsStraightLine(pointsX, pointsY) : false;
            var dpi = context.DpiScale;
            //switch (edgeRenderingMode)
            //{
            //    case EdgeRenderingMode.Automatic when rendersToPixels && isStraightLine:
            //    case EdgeRenderingMode.Adaptive when rendersToPixels && isStraightLine:
            //    case EdgeRenderingMode.PreferSharpness when rendersToPixels:
            //        var snapOffset = GetSnapOffset(context, thickness, edgeRenderingMode);
            //        if(dpi != 1)
            //        {
            //            SIMD.SnapTransform(pointsX, context.DpiScale, snapOffset);
            //            SIMD.SnapTransform(pointsY, context.DpiScale, snapOffset);
            //        }
            //        else
            //        {
            //            SIMD.SnapTransform(pointsX, snapOffset);
            //            SIMD.SnapTransform(pointsY, snapOffset);
            //        }
            //        break;
            //    default:                    
            //        if(dpi != 1)
            //        {
            //            SIMD.Transform(pointsX, context.DpiScale);
            //            SIMD.Transform(pointsY, context.DpiScale);
            //        }
            //        break;
            //}
            if(edgeRenderingMode == EdgeRenderingMode.PreferSharpness && context.RenderTarget != RenderTarget.VectorGraphic)
            {
                var snapOffset = GetSnapOffset(context, thickness, edgeRenderingMode);
                if (dpi != 1)
                {
                    SIMD.SnapTransform(pointsX, context.DpiScale, snapOffset);
                    SIMD.SnapTransform(pointsY, context.DpiScale, snapOffset);
                }
                else
                {
                    SIMD.SnapTransform(pointsX, snapOffset);
                    SIMD.SnapTransform(pointsY, snapOffset);
                }                
            }
            else if (dpi != 1)
            {
                SIMD.Transform(pointsX, context.DpiScale);
                SIMD.Transform(pointsY, context.DpiScale);
            }
            
            path.MoveTo(pointsX[0], pointsY[0]);
            for (int i = 1; i < pointsX.Length; i++)
            {
                path.LineTo(pointsX[i], pointsY[i]);
            }
            context.SkCanvas.DrawPath(path, paint);

            //static bool IsStraightLine(Span<float> pointsX, Span<float> pointsY)
            //{
            //    const float epsilon = 1e-5f;
            //    for (int i = 1; i < pointsX.Length; i++)
            //    {
            //        var x1 = pointsX[i - 1];
            //        var x2 = pointsX[i];
            //        var y1 = pointsY[i - 1];
            //        var y2 = pointsY[i];
            //        if (Math.Abs(x1 - x2) > epsilon && Math.Abs(y1 - y2) > epsilon)
            //        {
            //            return false;
            //        }
            //    }
            //    return true;
            //}
        }
    }
}
